package com.nus.fellowmark.modules.assignment.controller;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.excel.EasyExcel;
import com.nus.fellowmark.common.mongo.model.LoadFile;
import com.nus.fellowmark.common.mongo.service.MongoFileService;
import com.nus.fellowmark.common.response.ResponseEnum;
import com.nus.fellowmark.common.response.ServerResponseEntity;
import com.nus.fellowmark.common.utils.ExcelUtils;
import com.nus.fellowmark.common.utils.FileUtils;
import com.nus.fellowmark.entity.GradeEntity;
import com.nus.fellowmark.modules.assignment.dto.GradeDTO;
import com.nus.fellowmark.modules.assignment.service.FinalGradeService;
import com.nus.fellowmark.modules.assignment.service.GradeService;
import com.nus.fellowmark.modules.assignment.service.SubmissionService;
import com.nus.fellowmark.modules.assignment.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import com.nus.fellowmark.common.utils.PageUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;


/**
 * 
 *
 * @author Chen Ruoyi
 * @email chenruoyisz@gmail.com
 * @date 2023-02-10  
 */
@RestController
@RequestMapping("grade")
public class GradeController {
    @Autowired
    private GradeService gradeService;

    @Autowired
    private SubmissionService submissionService;

    @Autowired
    private MongoFileService mongoFileService;

    @Autowired
    private FinalGradeService finalGradeService;

    // TODO: can marker see the name or ID of the student?
    @ApiOperation("get assigned task")
    @RequestMapping("/getAssignedTask")
    public ServerResponseEntity getAssignedTasks() {
        Object loginId = StpUtil.getLoginId();
        List<MarkTaskVO> tasks = submissionService.getAssignedTasks(Integer.parseInt(loginId.toString()));
        return ServerResponseEntity.success(tasks);
    }

    @ApiOperation("get feedback from markers")
    @RequestMapping("/getFeedback/{assignmentId}")
    public ServerResponseEntity getFeedback(@PathVariable("assignmentId") Integer assignmentId) {
        Object loginId = StpUtil.getLoginId();
        List<MarkTaskVO> tasks = submissionService.getFeedback(Integer.parseInt(loginId.toString()), assignmentId);
        return ServerResponseEntity.success(tasks);
    }

    @ApiOperation("get submission file")
    @RequestMapping(value = "/getSubmissionFile/{fileKey}", produces = MediaType.APPLICATION_PDF_VALUE)
    public ServerResponseEntity getSubmissionFile(@PathVariable String fileKey, ServletOutputStream outputStream, HttpServletResponse response) {
        LoadFile loadFile = mongoFileService.downloadFile(fileKey);
        if (loadFile == null) {
            return ServerResponseEntity.fail(ResponseEnum.NO_SUCH_FILE);
        }

        // if want to view the file in the browser, comment this line; else to download the file, uncomment this.
//        response.setHeader("Content-Disposition", "attachment;filename="+loadFile.getFilename());
        response.setContentType("application/pdf;charset=UTF-8");

        InputStream in = loadFile.getInputStream();
        BufferedOutputStream out = new BufferedOutputStream(outputStream);
        Boolean outputFile = FileUtils.outputFile(out, in);
        if (!outputFile) {
            return ServerResponseEntity.fail(ResponseEnum.FAIL_TO_OUTPUT_FILE);
        }

        return ServerResponseEntity.success();
    }

    @ApiOperation("grade the assignment assigned to the student")
    @RequestMapping("/gradeAssignment")
    public ServerResponseEntity gradeAssignment(@RequestBody GradeDTO gradeDTO){
        Boolean result = gradeService.gradeAssignment(gradeDTO);
        if (!result) {
            return ServerResponseEntity.showFailMsg("Fail to grade!");
        }
        return ServerResponseEntity.success();
    }

    @ApiOperation("list the grade by pair Id and rubric Id")
    @RequestMapping("/listGradeByPairId/{pairId}/RubricId/{rubricId}")
    public ServerResponseEntity listGradeByPairIdAndRubricId(@PathVariable("pairId") Integer pairId, @PathVariable("rubricId") Integer rubricId) {
        GradeVO grade = gradeService.listGradeByPairIdAndRubricId(pairId, rubricId);
        return ServerResponseEntity.success(grade);
    }

    @ApiOperation("list the grade by pair Id only")
    @RequestMapping("/listGradeByPairId/{pairId}")
    public ServerResponseEntity listGradeByPairId(@PathVariable("pairId") Integer pairId) {
        List<GradeEntity> grades = gradeService.listGradeByPairId(pairId);
        return ServerResponseEntity.success(grades);
    }

    @ApiOperation("list grade by assignmentId")
    @RequestMapping("/listGradeByAssignmentId/{assignmentId}")
    public ServerResponseEntity listGradeByAssignmentId(@PathVariable("assignmentId") Integer assignmentId) {
       List<GradeAsgVO> gradeVOS = gradeService.listGradeByAssignmentId(assignmentId);
       return ServerResponseEntity.success(gradeVOS);
    }

    @GetMapping("/downloadGrades/{assignmentId}")
    public void downloadGrades(@PathVariable("assignmentId") Integer assignmentId, HttpServletResponse response) throws IOException {
        List<FinalGradeVO> finalGradeVOS = finalGradeService.calculateFinalGrade(assignmentId);
        ExcelUtils.download(response, FinalGradeVO.class, finalGradeVOS, "grades_" + assignmentId);
    }

    @ApiOperation("list grade by studentId")
    @RequestMapping("/listGradeByStuId/{assignmentId}")
    public ServerResponseEntity listGradeByStuId(@PathVariable Integer assignmentId) {
        Object stuId = StpUtil.getLoginId();
        List<GradeStuVO> gradeVOS = gradeService.listGradeByStuId(Integer.parseInt(stuId.toString()), assignmentId);
        return ServerResponseEntity.success(gradeVOS);
    }


    @SaCheckRole(value = {"admin", "super-admin", "staff"}, mode = SaMode.OR)
    @ApiOperation("list grade")
    @RequestMapping("/list")
    public ServerResponseEntity list(@RequestParam Map<String, Object> params){
        PageUtils page = gradeService.queryPage(params);

        return ServerResponseEntity.success("page", page);
    }


    @ApiOperation("select grade by id ")
    @RequestMapping("/info/{id}")
    public ServerResponseEntity info(@PathVariable("id") Integer id){
		GradeEntity grade = gradeService.getById(id);

        return ServerResponseEntity.success("grade", grade);
    }

    @ApiOperation("save grade")
    @RequestMapping("/save")
    public ServerResponseEntity save(@RequestBody GradeEntity grade){
		gradeService.save(grade);

        return ServerResponseEntity.success();
    }

    @ApiOperation("update grade")
    @RequestMapping("/update")
    public ServerResponseEntity update(@RequestBody GradeEntity grade){
		gradeService.updateById(grade);

        return ServerResponseEntity.success();
    }

    @ApiOperation("delete grade")
    @RequestMapping("/delete")
    public ServerResponseEntity delete(@RequestBody Integer[] ids){
		gradeService.removeByIds(Arrays.asList(ids));

        return ServerResponseEntity.success();
    }

}
